﻿using System;

namespace CSharpConsoleTestSolution.Demo
{
    public class P12_Operator3
    {
        /**
         * 6.1.2 隐式数值转换: 时间07:40
         * 隐式数值转换为:
         * 从 sbyte  到 short、int、long、float、double 或decimal.
         * 从 byte   到 short、ushort、int、uint、long、ulong、float、double 或 decimal.
         * 从 short  到 int、long、float、double 或decimal.
         * 从 ushort 到 int、uint、long、ulong、float、double 或decimal.
         * 从 int    到 long、float、double 或 decimal.
         * 从 uint   到 long、ulong、float、double 或decimal.
         * 从 long   到 float、double 或decimal.
         * 从 ulong  到 float、double 或decimal.
         * 从 char   到 ushort、int、uint、long、ulong、float、double 或 decimal.
         * 从 float  到 double.
         * 
         * 从 int、uint、long或ulong 到 float 的转换以及从 long或ulong 到 double 的转换可能导致精度损失，但决不会影响数值大小。其他的隐式数值转换决不会丢失任何信息。
         * 不存在向 char 类型的隐式转换，因此其他整型的值不会自动转换为char 类型。
         */


        /**
         * Parse 和 Convert, 数据类型转换 : 时间28:48
         */
        public static void parse_convert() {
            string str1 = "123.4567";
            Console.WriteLine("请输入非double字符(1e2), 用于测试 TryParse:");
            string str2 = Console.ReadLine();   //从命令行读取
            string str3 = "456.78";

            double d1 = double.Parse(str1);                 //有可能报错
            double d2 = -1;
            bool success = double.TryParse(str2, out d2);   //解析错误后, d2强制赋值0
            double d3 = Convert.ToDouble(str3);             //有可能报错
            
            Console.WriteLine($"double.TryParse(\"{str2}\", d2) success: {success}");
            Console.WriteLine($"d1 = {d1}, d2 = {d2}, d3 = {d3}");
        }


        /**
         * 显式类型转换 : 时间 35:20
         * explicit /ɪkˈsplɪsɪt/ : adj.清楚明白的，明确的，详述的；直截了当的，坦率的；赤裸裸表现性爱（或暴力）的，露骨的
         *                         n.（手稿、早期印刷品或礼拜仪式上唱诗的）结束语
         */
        public static void explicit_operator_exam() {
            Stone stone = new Stone();
            stone.Age = 5000;
            Monkey monkey = (Monkey)stone;  //if没有 explicit 方法, 强转会报错, 编译不过
            Console.WriteLine(monkey.Age);
        }
        
        public class Stone {
            public int Age;
            //显式类型转换, 看起来像构造方法
            public static explicit operator Monkey(Stone stone) {
                Monkey monkey = new Monkey();
                monkey.Age = stone.Age / 500;
                return monkey;
            }
            
            //隐式类型转换, 看起来像构造方法
            public static implicit operator Monkey_6Ears(Stone stone) {
                Monkey_6Ears monkey = new Monkey_6Ears();
                monkey.Age = stone.Age / 500;
                return monkey;
            }
        }
        
        public class Monkey {
            public int Age;
        }
        public class Monkey_6Ears {
            public int Age;
        }

        /**
         * 隐式类型转换 : 时间 35:25
         * implicit /ɪmˈplɪsɪt/  : adj.含蓄的，未言明的；内含的，固有的；无疑问的，无保留的；（函数）隐式的，隐的
         */
        public static void implicit_operator_exam() {
            Stone stone = new Stone();
            stone.Age = 5000;
            Monkey_6Ears monkey6Ears = (Monkey_6Ears)stone; //可以去掉括号
            Console.WriteLine(monkey6Ears.Age);
        }


        /**
         * 7.8.2 除法运算符 (+z / +y = +z): 时间 38:55
         *          +y      -y      +0      -0      +∞      -∞      NaN
         * +x       +z      -z      +0      -0      +∞      -∞      NaN
         * -x       -z      +z      -0      +0      -∞      +∞      NaN
         * +0       +0      -0      +0      -0      NaN     NaN     NaN
         * -0       -0      +0      -0      +0      NaN     NaN     NaN
         * +∞       +∞      -∞      NaN     NaN     +∞      -∞      NaN
         * -∞       -∞      +∞      NaN     NaN     -∞      +∞      NaN
         * NaN      NaN     NaN     NaN     NaN     NaN     NaN     NaN
         * 
         * 除法 : 时间 45:15
         */
        public static void divide() {
            double x = double.PositiveInfinity;
            double y = double.NegativeInfinity;
            //                  x = ∞, y = -∞, x/y = NaN
            Console.WriteLine($"x = {x}, y = {y}, x/y = {x / y}");
        }

        /**
         * 比较字符串: 时间 1:00:15
         */
        public static void compare() {
            string str1 = "Abc";
            string str2 = "Abc";
            
            bool equals = str1.Equals(str2);
            bool equals2 = str1 == str2;
            int compare = string.Compare(str1, str2);           //对齐2个字符串, 按顺序比较
            int compare2 = String.CompareOrdinal(str1, str2);   //对齐2个字符串, 按顺序比较
            
            Console.WriteLine(equals);  //True
            Console.WriteLine(equals2); //True
            Console.WriteLine(compare); //0
            Console.WriteLine(compare2); //0
        }


        /**
         * is, as: 时间 1:07:00
         */
        public static void is_as() {
            string str1 = "Abc";
            bool sio = str1 is object;  //is

            object obj = "Abc";
            string dsf = obj as string; //as
            
            Console.WriteLine(sio);
            Console.WriteLine(dsf?.Length);
            Console.WriteLine((obj as string)?.Length); //? 安全转换, 防止null
        }

        /**
         * ? 可空, ?? 判断是否可空 : 时间 1:19:55
         */
        public static void nullable_isnull() {
            Nullable<int> a = null; //Nullable 可空类型
            int? b = null;
            int? c = null;
            int? d = null;

            a = 100;
            b = 200;
            c = c.GetValueOrDefault(1); //if c没有值, 赋值默认值1
            d = d ?? 2;                 //null 合并操作符, if d没有值, 赋值默认值2
            Console.WriteLine($"a.HasValue = {a.HasValue}, a.Value = {a.Value}");   //a.HasValue = True, a.Value = 100
            Console.WriteLine($"b.HasValue = {b.HasValue}, b.Value = {b.Value}");   //b.HasValue = True, b.Value = 200
            Console.WriteLine($"c.HasValue = {c.HasValue}, c.Value = {c.Value}");   //c.HasValue = True, c.Value = 1
            Console.WriteLine($"d.HasValue = {d.HasValue}, d.Value = {d.Value}");   //d.HasValue = True, d.Value = 2
        }


        /**
         * 条件操作符(? x : y) : 时间 1:24:30
         */
        public static void conditional_operator() {
            int x = 80;
            string result = x >= 60 ? "Pass" : "Failure";
            Console.WriteLine(result);
        }
    }
}